package ai.people.netmon.auth.service;

import ai.people.netmon.framework.constant.NmSystemConstant;
import ai.people.netmon.framework.constant.OAuth2Constant;
import ai.people.netmon.framework.domain.ucenter.ext.IssueToken;
import ai.people.netmon.framework.domain.ucenter.request.LoginRequest;
import ai.people.netmon.framework.domain.ucenter.request.LoginUser;
import ai.people.netmon.framework.exception.enums.AuthExceptionEnum;
import ai.people.netmon.framework.exception.type.AuthException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.*;

/**
 * 身份验证服务impl
 *
 * @author yuanqinglong
 * @date 2022/2/21 13:11
 */
@Slf4j
@Service
@Deprecated
public class AuthenticateServiceImpl implements AuthenticateService {

    @Value("${auth.clientId}")
    private String clientId;

    @Value("${auth.clientSecret}")
    private String clientSecret;

    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Value("${oauth.token.address}")
    private String tokenAddress;


    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RedisTokenStore redisTokenStore;


    /**
     * 进行身份验证
     *
     * @param loginRequest 登录请求
     * @return {@link Map}<{@link String}, {@link Object}>
     */
    @Override
    public Map<String, Object> authenticate(LoginRequest loginRequest) throws IOException {
        // 设置2个post参数，一个是scope、一个是q
        List<NameValuePair> parameters = new ArrayList<>(0);
        parameters.add(new BasicNameValuePair(OAuth2Constant.MATE_USERNAME, loginRequest.getUsername()));
        parameters.add(new BasicNameValuePair(OAuth2Constant.PASSWORD, loginRequest.getPassword()));
        parameters.add(new BasicNameValuePair(OAuth2Constant.GRANT_TYPE, OAuth2Constant.PASSWORD));
        return this.createToken(parameters, loginRequest.getClient_id(), loginRequest.getClient_secret());
    }


    /**
     * 刷新令牌
     *
     * @param refreshToken 刷新令牌
     * @return {@link IssueToken}
     */
    @Override
    public Map<String, Object> refreshToken(String refreshToken) throws IOException {
        //定义body
        //LinkedMultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        //body.add(OAuth2Constant.GRANT_TYPE, OAuth2Constant.REFRESH_TOKEN);
        //body.add(OAuth2Constant.REFRESH_TOKEN, refreshToken);
        List<NameValuePair> parameters = new ArrayList<>(0);
        parameters.add(new BasicNameValuePair(OAuth2Constant.GRANT_TYPE, OAuth2Constant.REFRESH_TOKEN));
        parameters.add(new BasicNameValuePair(OAuth2Constant.REFRESH_TOKEN, refreshToken));
        return this.createToken(parameters, null, null);
    }


    /**
     * 创建令牌
     *
     * @param parameters   @return {@link IssueToken}
     * @param clientId     客户机id
     * @param clientSecret 客户秘密
     * @return {@link Map}<{@link String}, {@link Object}>
     */
    public Map<String,Object> createToken(List<NameValuePair> parameters, String clientId, String clientSecret) throws IOException {
        //令牌申请的地址
        String authUrl = tokenAddress + contextPath + OAuth2Constant.OAUTH_TOKEN;
        CloseableHttpResponse execute;
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost(authUrl);
            // 构造一个form表单式的实体
            UrlEncodedFormEntity formEntity;
            try {
                formEntity = new UrlEncodedFormEntity(parameters);
                // 将请求实体设置到httpPost对象中
                httpPost.setEntity(formEntity);
                clientId = Optional.ofNullable(clientId).orElse(this.clientId);
                clientSecret = Optional.ofNullable(clientSecret).orElse(this.clientSecret);
                httpPost.setHeader(NmSystemConstant.AUTH_HEADER_AUTHORIZATION, this.getHttpBasic(clientId, clientSecret));
                execute = httpClient.execute(httpPost);
            } catch (IOException e) {
                log.error("请求认证请求异常", e);
                throw new AuthException(AuthExceptionEnum.INTERNAL_SERVICE_EXCEPTION);
            }
        }
        org.apache.http.HttpEntity httpEntity = execute.getEntity();
        String tokenJson;
        try {
            tokenJson = EntityUtils.toString(httpEntity, "UTF-8");
        } catch (IOException e) {
            log.error("请求认证Token转换异常", e);
            throw new AuthException(AuthExceptionEnum.INTERNAL_SERVICE_EXCEPTION);
        }
        JSONObject jsonObject = JSONObject.parseObject(tokenJson);
        log.info("认证json信息：{}", jsonObject);
        //if (!Objects.equals(execute.getStatusLine().getStatusCode(), HttpStatus.OK.value())) {
        //    this.exceptionHandler(jsonObject);
        //}
        return jsonObject;
    }




    /**
     * 检查令牌
     *
     * @param token 令牌
     * @return {@link LoginUser}
     */
    @Override
    public LoginUser checkToken(String token) {
        //实例地址
        String authUrl = tokenAddress + contextPath + OAuth2Constant.OAUTH_CHECK_TOKEN;
        //URI uri = serviceInstance.getUri();
        //String authUrl = uri + OAuth2Constant.OAUTH_CHECK_TOKEN;
        // 请求体
        LinkedMultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.add(OAuth2Constant.TOKEN, token);
        // 请求头信息
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.setBasicAuth(clientId, clientSecret);
        HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(body, headers);
        ResponseEntity<Map> result = restTemplate.exchange(authUrl, HttpMethod.POST, httpEntity, Map.class);
        if (Objects.equals(result.getStatusCode(), HttpStatus.BAD_REQUEST)) {
            throw new AuthException(AuthExceptionEnum.INVALID_TOKEN);
        }
        Map resultBody = result.getBody();
        return JSON.parseObject(JSON.toJSONString(resultBody), LoginUser.class);
    }


    /**
     * 注销
     *
     * @param token 令牌
     */
    @Override
    public void logout(String token) {
        redisTokenStore.removeAccessToken(token);
    }
}
